﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using com.tomsawyer.drawing;
using com.tomsawyer.licensing;
using MacomberMapSystem.Common.Serialization;
using System.Data.Common;
using System.Drawing;
using com.tomsawyer.service.layout;
using com.tomsawyer.service;
using com.tomsawyer.service.layout.client;
using com.tomsawyer.service.layout.xml;
using MacomberMapSystem.Common.Internals;
using java.io;
using com.tomsawyer.drawing.geometry;
using com.tomsawyer.drawing.complexity;
using MacomberMapSystem.Common.User_Interfaces.CIM_Browser;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.CIM;
using MacomberMapSystem.Common.Integration;

namespace MacomberMapSystem.Common.User_Interfaces.One_Lines
{
    /// <summary>
    /// This class is responsible for executing a Tom Sawyer layout against a one-line
    /// </summary>
    public static class clsTomSawyer
    {
        /// <summary>
        /// Perform Tom Sawyer layout against a specified one-line
        /// </summary>
        /// <param name="FrontEndElements"></param>
        /// <param name="Repository"></param>
        public static void RunLayout(IEnumerable<CIM_Element_FrontEnd> FrontEndElements, MM_Repository Repository)
        {
            //First, set up for TSL
            Dictionary<CIM_Element_FrontEnd, TSDNode> Elements = new Dictionary<CIM_Element_FrontEnd, TSDNode>();
            TSLicenseManager.setUserName(Repository.UserName);
            //TSLicenseManager.initTSSLicensing();
            using (DbCommand dCmd = Repository.Db.CreateCommand("SELECT VALUE FROM MM_CONFIGURATION WHERE \"PARAMETER\"=:0", "TomSawyerLayout"))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                if (dRd.Read())
                {
                    XmlDocument xConfig = new XmlDocument();
                    xConfig.LoadXml((string)dRd["Value"]);
                    java.util.Properties p = new java.util.Properties();
                    foreach (XmlAttribute xAttr in xConfig.DocumentElement.Attributes)
                        p.put(xAttr.Name, xAttr.Value);
                    TSLicenseManager.initTSSLicensing(p); //xConfig.DocumentElement.Attributes["protocol"].Value, xConfig.DocumentElement.Attributes["centralServerHostName"].Value, XmlConvert.ToInt32(xConfig.DocumentElement.Attributes["port"].Value), xConfig.DocumentElement.Attributes["licenseName"].Value,"");
                }

            TSDGraphManager graphManager = new TSDGraphManager();
            TSDGraph NewGraph = (TSDGraph)graphManager.addGraph();
            graphManager.setMainDisplayGraph(NewGraph);

            //Add in our elements
            foreach (CIM_Element_FrontEnd FrontEndElem in FrontEndElements)
            {
                TSDNode NewNode = (TSDNode)NewGraph.addNode();
                NewNode.setSize(FrontEndElem.Width, FrontEndElem.Height);
                NewNode.setCenter(FrontEndElem.Left + (FrontEndElem.Width / 2), FrontEndElem.Top + (FrontEndElem.Height / 2));
                NewNode.setUserObject(FrontEndElem);
                Elements.Add(FrontEndElem, NewNode);
            }

            //Add in our outgoing linkages
            foreach (CIM_Element_FrontEnd FrontEndElem in FrontEndElements)
                foreach (CIM_Element_FrontEnd FrontEndElem2 in FrontEndElem.OutgoingElements)
                    NewGraph.addEdge(Elements[FrontEndElem], Elements[FrontEndElem2]);

            //Apply our layout.
            TSLayoutProxy layoutProxy = new TSLayoutProxy();
            TSServiceInputData inputData = new TSServiceInputData(TSLayoutServiceName.TYPE);
            TSOrthogonalLayoutInputTailor layoutInputTailor = new TSOrthogonalLayoutInputTailor(inputData, NewGraph);
            layoutInputTailor.setAsCurrentLayoutStyle();
            TSLayoutInputTailor tailor = new TSLayoutInputTailor(inputData, graphManager);
            tailor.setAsCurrentOperation();

            TSServiceOutputData outputData = new TSServiceOutputData();
            layoutProxy.run(inputData, outputData);
            TSApplyLayoutResults applyResults = new TSApplyLayoutResults();
            applyResults.apply(inputData, outputData);

            //Make sure our subgraphs are included
            java.util.ArrayList nestedGraphs = new java.util.ArrayList();
            TSNestingManager.buildAllNestedGraphList(NewGraph, nestedGraphs, false);
            foreach (TSDGraph childGraph in nestedGraphs)            
                inputData.setOption(childGraph, TSBaseGeneralLayoutConstants.LAYOUT_STYLE, TSLayoutConstants.LAYOUT_STYLE_ORTHOGONAL);


            //Determine our bounds of our updated components
            Point MinPoint = Point.Empty;
            foreach (TSDNode Node in ExtractNodes(NewGraph))
            {
                MinPoint.X = Math.Min(MinPoint.X, (int)Node.getLeft());
                MinPoint.Y = Math.Min(MinPoint.Y, (int)-Node.getBottom());
            }

            //Apply our positioning
            foreach (TSDNode Node in ExtractNodes(NewGraph))
            {
                Point NewCenter = new Point((int)Node.getCenterX() - MinPoint.X, (int)-Node.getCenterY() + 80 - MinPoint.Y);
                Size NewSize = new Size((int)Node.getWidth(), (int)Node.getHeight());
                (Node.getUserObject() as CIM_Element_FrontEnd).Bounds = new Rectangle(NewCenter, NewSize);
            }                               
        }

        /// <summary>
        /// Perform Tom Sawyer layout against a specified one-line
        /// </summary>
        /// <param name="xOneLine"></param>
        /// <param name="Repository"></param>
        public static void RunLayout(XmlDocument xOneLine, MM_Repository Repository)
        {
            //First, set up for TSL
            Dictionary<XmlElement, TSDNode> Elements = new Dictionary<XmlElement, TSDNode>();
            System.Console.WriteLine("About to initialize the licensing for " + xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value);
            try
            {
                TSLicenseManager.setUserName(Repository.UserName);

                //TSLicenseManager.initTSSLicensing();
                using (DbCommand dCmd = Repository.Db.CreateCommand("SELECT VALUE FROM MM_CONFIGURATION WHERE \"PARAMETER\"=:0", "TomSawyerLayout"))
                using (DbDataReader dRd = dCmd.ExecuteReader())
                    if (dRd.Read())
                    {
                        XmlDocument xConfig = new XmlDocument();
                        xConfig.LoadXml((string)dRd["Value"]);
                        java.util.Properties p = new java.util.Properties();
                        foreach (XmlAttribute xAttr in xConfig.DocumentElement.Attributes)
                            p.put(xAttr.Name, xAttr.Value);
                        TSLicenseManager.initTSSLicensing(p); //xConfig.DocumentElement.Attributes["protocol"].Value, xConfig.DocumentElement.Attributes["centralServerHostName"].Value, XmlConvert.ToInt32(xConfig.DocumentElement.Attributes["port"].Value), xConfig.DocumentElement.Attributes["licenseName"].Value,"");
                    }
                System.Console.WriteLine("Initialized the licensing for " + xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value);
            }
            catch
            {
                System.Console.WriteLine("Error initializing licensing for " + xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value);
            }

            
            TSDGraphManager graphManager=null;
             TSDGraph NewGraph=null;
             bool LicenseInitialized = false;
             while (!LicenseInitialized)
                try
                {
                    graphManager = new TSDGraphManager();
                    NewGraph = (TSDGraph)graphManager.addGraph();
                    LicenseInitialized = true;
                }
                catch (Exception ex)
                {
                    System.Console.WriteLine("Pausing to re-attempt licensing for " + xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value + ": " + ex.Message);

                    System.Threading.Thread.Sleep(500);
                    System.Windows.Forms.Application.DoEvents();
                }

           
            graphManager.setMainDisplayGraph(NewGraph);            
          
            //First, create our list of elements and thier TSD nodes
            Dictionary<String, TSDGraph> SubGraphs = new Dictionary<string, TSDGraph>();
            foreach (XmlElement xElem in xOneLine.SelectNodes("One_Line/Elements/*"))
                try
                {
                    AddComponent(xElem, Elements, null, NewGraph, SubGraphs, graphManager);
                }
                catch 
                { }

            //Now, pull in our collection of nodes
            foreach (XmlElement xNode in xOneLine.SelectNodes("One_Line/Nodes/*"))
                try
                {
                    AddComponent(xNode, Elements, null, NewGraph, SubGraphs, graphManager);
                }
                catch
                {
                }
            Point MinPoint;
            ApplyLayout(graphManager, NewGraph, xOneLine, out MinPoint);
            PullLayoutToXml(NewGraph, MinPoint, xOneLine);

            foreach (TSDNode Node in Elements.Values)
                Node.dispose();
            foreach (TSDGraph SubGraph in SubGraphs.Values)
                SubGraph.dispose();
            NewGraph.dispose();
            graphManager.dispose();
        }

        /// <summary>
        /// Apply our Tom Sawyer Layout to our connectivity
        /// </summary>
        /// <param name="graphManager"></param>
        /// <param name="NewGraph"></param>
        /// <param name="MinPoint"></param>
        /// <param name="xOneLine"></param>
        private static void ApplyLayout(TSDGraphManager graphManager, TSDGraph NewGraph, XmlDocument xOneLine, out Point MinPoint)
        {
            //Now, apply our layout
            TSLayoutProxy layoutProxy = new TSLayoutProxy();
            TSServiceInputData inputData = new TSServiceInputData(TSLayoutServiceName.TYPE);


            TSOrthogonalLayoutInputTailor layoutInputTailor = new TSOrthogonalLayoutInputTailor(inputData, NewGraph);
            layoutInputTailor.setAsCurrentLayoutStyle();

            TSLayoutInputTailor tailor = new TSLayoutInputTailor(inputData, graphManager);
            tailor.setAsCurrentOperation();

            //Make sure our subgraphs are included
            java.util.ArrayList nestedGraphs = new java.util.ArrayList();
            TSNestingManager.buildAllNestedGraphList(NewGraph, nestedGraphs, false);
            foreach (TSDGraph childGraph in nestedGraphs)
            {
                inputData.setOption(childGraph, TSBaseGeneralLayoutConstants.LAYOUT_STYLE, TSLayoutConstants.LAYOUT_STYLE_ORTHOGONAL);
                foreach (TSDNode graphNode in childGraph.nodes().toArray())
                    if ((graphNode.getUserObject() as XmlElement).Name == "Switch")
                        layoutInputTailor.setAttachmentSide(graphNode, TSLayoutConstants.ATTACHMENT_SIDE_LEFT_OR_RIGHT);
            }
            
            //Go through all components and assign their orientations



            /*TSGeneralLayoutInputTailor layoutTailor = new TSGeneralLayoutInputTailor(inputData);
            layoutTailor.setLayoutStyle(TSLayoutConstants.LAYOUT_STYLE_ORTHOGONAL);
                layoutTailor.setGraph(NewGraph);
                layoutTailor.setAsCurrentLayoutStyle();
            
            //Make sure our subgraphs are included
            java.util.ArrayList nestedGraphs = new java.util.ArrayList();
            TSNestingManager.buildAllNestedGraphList(NewGraph,nestedGraphs,false);

            foreach (TSDGraph childGraph in nestedGraphs)
                inputData.setOption(childGraph, TSBaseGeneralLayoutConstants.LAYOUT_STYLE,TSLayoutConstants.LAYOUT_STYLE_ORTHOGONAL);
            
           
            TSLayoutInputTailor inputTailor = new TSLayoutInputTailor(inputData, graphManager);
            inputTailor.setAsCurrentOperation();
            inputTailor.setIncrementalLayout(false);*/

            TSServiceOutputData outputData = new TSServiceOutputData();
            layoutProxy.run(inputData, outputData);
            TSApplyLayoutResults applyResults = new TSApplyLayoutResults();
            applyResults.apply(inputData, outputData);        

            /*TSLayoutXMLWriter xW = new TSLayoutXMLWriter(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value + "-PostMerge.tsl"));
            xW.setGraphManager(graphManager);
            xW.write();*/

            CollapsePoints(NewGraph);            

            /*//Apply edge routing
            TSRoutingInputTailor RoutingTailor = new TSRoutingInputTailor(inputData, graphManager);
            RoutingTailor.setAsCurrentOperation();
            RoutingTailor.setEdgeList(NewGraph.edges());
            outputData = new TSServiceOutputData();
            layoutProxy.run(inputData, outputData);
            applyResults = new TSApplyLayoutResults();
            applyResults.apply(inputData, outputData);

            // CollapsePoints(NewGraph);

            //Write out our post-merged file
            xW = new TSLayoutXMLWriter(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), xOneLine.DocumentElement.Attributes["BaseElement.Name"].Value + "-PostMerge2.tsl"));
            xW.setGraphManager(graphManager);
            xW.write();

            */
            //Determine our bounds of our updated components
            MinPoint = Point.Empty;
            foreach (TSDNode Node in ExtractNodes(NewGraph))
            {
                XmlElement Elem = Node.getUserObject() as XmlElement;
                MinPoint.X = Math.Min(MinPoint.X, (int)Node.getLeft());
                MinPoint.Y = Math.Min(MinPoint.Y, (int)-Node.getBottom());
                if (!Node.labels().isEmpty())
                {
                    MinPoint.X = Math.Min(MinPoint.X, (int)(Node.labels().get(0) as TSLabel).getLeft());
                    MinPoint.Y = Math.Min(MinPoint.Y, (int)-(Node.labels().get(0) as TSLabel).getBottom());
                }
            }
        }

        /// <summary>
        /// Collapse our points as needed
        /// </summary>
        /// <param name="NewGraph"></param>
        private static void CollapsePoints(TSDGraph NewGraph)
        {
            //Go through and remove and reorient elements that have two or more edges going into the same side, and determine our element orientations
            java.util.Iterator NodeIter = NewGraph.nodes().iterator();
            while (NodeIter.hasNext())
            {
                TSDNode InNode = NodeIter.next() as TSDNode;
                TSDGraph ChildGraph = (TSDGraph)InNode.getChildGraph();
                List<TSDNode> NodesToProcess = new List<TSDNode>();
                if (ChildGraph == null)
                    NodesToProcess.Add(InNode);
                else
                    foreach (TSDNode Node in ChildGraph.nodes().toArray())
                        NodesToProcess.Add(Node);

                foreach (TSDNode Node in NodesToProcess)
                {


                    TSDEdge[] ThisNodeEdges = new TSDEdge[Node.getAllIncidentEdges().size()];
                    int[] Connections = new int[4];
                    int TotalConnections = 0;

                    Array.Copy(Node.getAllIncidentEdges().toArray(), ThisNodeEdges, ThisNodeEdges.Length);

                    MM_OneLine_Element.enumOrientations ClosestOrientation = MM_OneLine_Element.enumOrientations.Unknown;
                    Double ClosestDistance = Double.MaxValue;

                    foreach (TSDEdge NodeEdge in ThisNodeEdges)
                    {
                        TSConstPoint NodePt = (NodeEdge.getSourceNode() == Node) ? NodeEdge.getSourcePoint() : NodeEdge.getTargetPoint();
                        CheckCoordinates(NodePt.getX(), Node.getLeft(), Connections, ref ClosestOrientation, ref ClosestDistance, MM_OneLine_Element.enumOrientations.Right, 0);
                        CheckCoordinates(NodePt.getX(), Node.getRight(), Connections, ref ClosestOrientation, ref ClosestDistance, MM_OneLine_Element.enumOrientations.Left, 1);
                        CheckCoordinates(NodePt.getY(), Node.getBottom(), Connections, ref ClosestOrientation, ref ClosestDistance, MM_OneLine_Element.enumOrientations.Up, 2);
                        CheckCoordinates(NodePt.getY(), Node.getTop(), Connections, ref ClosestOrientation, ref ClosestDistance, MM_OneLine_Element.enumOrientations.Down, 3);
                        TotalConnections++;
                    }

                    //Determine our last points into our element
                    MM_OneLine_Element.enumOrientations Orientation = MM_OneLine_Element.enumOrientations.Unknown;
                    TSConstPoint NewLastPoint = new TSConstPoint();

                    //If we have all our connections to one side, move our node to adjust, and change our orientation.
                    if (Connections.Sum() == 0 && TotalConnections == 1)
                        Orientation = ClosestOrientation;
                    else if ((Connections[0] == TotalConnections || Connections[1] == TotalConnections) && TotalConnections > 1)
                    {
                        Orientation = MM_OneLine_Element.enumOrientations.Vertical;
                        TSConstPoint LastPoint = new TSConstPoint();
                        foreach (TSDEdge NodeEdge in ThisNodeEdges)
                            if (NodeEdge.bendPoints().size() > 0)
                                if (NodeEdge.getTargetNode() == Node)
                                    LastPoint = NodeEdge.bendPoints().get(NodeEdge.bendPoints().size() - 1) as TSConstPoint;
                                else
                                    LastPoint = NodeEdge.bendPoints().get(0) as TSConstPoint;


                        NewLastPoint = new TSConstPoint(LastPoint.getX(), Node.getCenterY());
                        Node.setCenter(NewLastPoint);
                    }
                    else if ((Connections[2] == TotalConnections || Connections[3] == TotalConnections) && TotalConnections > 1)
                    {
                        Orientation = MM_OneLine_Element.enumOrientations.Horizontal;
                        TSConstPoint LastPoint = new TSConstPoint();
                        foreach (TSDEdge Edge in ThisNodeEdges)
                            if (Edge.bendPoints().size() > 0)
                                LastPoint = Edge.getTargetNode() == Node ? Edge.bendPoints().get(Edge.bendPoints().size() - 1) as TSConstPoint : Edge.bendPoints().get(0) as TSConstPoint;

                        //Go through our edges until we find one matching the source, and pull that one if possible.

                        //TSConstPoint LastPoint = ThisNodeEdges[0].getTargetNode() == Node ? ThisNodeEdges[0].bendPoints().get(ThisNodeEdges[0].bendPoints().size() - 1) as TSConstPoint : ThisNodeEdges[0].bendPoints().get(0) as TSConstPoint;
                        NewLastPoint = new TSConstPoint(Node.getCenterX(), LastPoint.getY());
                        Node.setCenter(NewLastPoint);
                    }
                    else if (Connections[0] == TotalConnections)
                        Orientation = MM_OneLine_Element.enumOrientations.Right;
                    else if (Connections[1] == TotalConnections)
                        Orientation = MM_OneLine_Element.enumOrientations.Left;
                    else if (Connections[2] == TotalConnections)
                        Orientation = MM_OneLine_Element.enumOrientations.Up;
                    else if (Connections[3] == TotalConnections)
                        Orientation = MM_OneLine_Element.enumOrientations.Down;
                    else if (Connections[3] + Connections[2] > Connections[0] + Connections[1])
                        Orientation = MM_OneLine_Element.enumOrientations.Vertical;
                    else
                        Orientation = MM_OneLine_Element.enumOrientations.Horizontal;

                    XmlElement xElem = (Node.getUserObject() as XmlElement);
                    xElem.Attributes["Orientation"].Value = Orientation.ToString();



                    //Flip our size if vertical
                    if (xElem.Name != "Node")
                        if (Orientation == MM_OneLine_Element.enumOrientations.Horizontal || Orientation == MM_OneLine_Element.enumOrientations.Left || Orientation == MM_OneLine_Element.enumOrientations.Right)
                            Node.setSize(Math.Max(Node.getHeight(), Node.getWidth()), Math.Min(Node.getHeight(), Node.getWidth()));
                        else
                            Node.setSize(Math.Min(Node.getHeight(), Node.getWidth()), Math.Max(Node.getHeight(), Node.getWidth()));
                }
            }
        }

        /// <summary>
        /// Check our coordinates to see if we have updatable components
        /// </summary>
        /// <param name="InflectionPoint"></param>
        /// <param name="NodePoint"></param>
        /// <param name="Connections"></param>
        /// <param name="ClosestOrientation"></param>
        /// <param name="ClosestDistance"></param>
        /// <param name="AssociatedOrientation"></param>
        /// <param name="Index"></param>
        private static void CheckCoordinates(double InflectionPoint, double NodePoint, int[] Connections, ref MM_OneLine_Element.enumOrientations ClosestOrientation, ref double ClosestDistance, MM_OneLine_Element.enumOrientations AssociatedOrientation, int Index)
        {
            if ((Index % 2) == 0 && InflectionPoint - NodePoint <= 1E-14)
                Connections[Index]++;
            else if ((Index % 2) == 1 && InflectionPoint - NodePoint >= -1E-14)
                Connections[Index]++;

            double ThisDist = Math.Abs(InflectionPoint - NodePoint);
            if (ThisDist < ClosestDistance)
            {
                ClosestDistance = ThisDist;
                ClosestOrientation = AssociatedOrientation;
            }
        }


        /// <summary>
        /// Add a component to our collection of TSD nodes
        /// </summary>
        /// <param name="xElem"></param>
        /// <param name="Elements"></param>
        /// <param name="ParentNode"></param>
        /// <param name="Graph"></param>
        /// <param name="SubGraphs"></param>
        /// <param name="graphManager"></param>        
        private static TSDNode AddComponent(XmlElement xElem, Dictionary<XmlElement, TSDNode> Elements, TSDNode ParentNode, TSDGraph Graph, Dictionary<String, TSDGraph> SubGraphs, TSDGraphManager graphManager)
        {
            TSDGraph WorkingGraph;

            //Determine where the equipment should be placed
            if (xElem.Name == "Line")
                WorkingGraph = Graph;
            else if (xElem != null && ParentNode != null)
            {
                TSLabel NewLabel = ParentNode.addLabel();
                Rectangle Bounds = MM_Serializable<Rectangle>.ConvertObject(xElem.HasAttribute("LabelBounds") ? xElem.Attributes["LabelBounds"].Value : xElem.Attributes["Bounds"].Value, null);
                NewLabel.setSize(Bounds.Width, Bounds.Height);
                NewLabel.setCenter(Bounds.Left + (Bounds.Width / 2), Bounds.Top + (Bounds.Height / 2));
                NewLabel.setName(xElem.Attributes["DescriptorText"].Value);
                NewLabel.setUserObject(xElem);                
                return ParentNode;
            }
            else if (xElem == null)
                return null;

            else if (!SubGraphs.TryGetValue(xElem.Attributes["BaseElement.SubLongName"].Value, out WorkingGraph))
            {
                TSDNode SubNode = (TSDNode)Graph.addNode();
                SubNode.setName(xElem.Attributes["BaseElement.SubLongName"].Value);
                SubNode.setUserObject(xElem.Attributes["BaseElement.SubLongName"].Value);
                SubNode.addLabel().setName(xElem.Attributes["BaseElement.SubLongName"].Value);
                using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
                using (Font f = new Font("Arial", 12, FontStyle.Bold))
                {
                    Size LabelSize = Size.Ceiling(g.MeasureString(xElem.Attributes["BaseElement.SubName"].Value, f));
                    (SubNode.labels().get(0) as TSLabel).setSize(LabelSize.Width+4, LabelSize.Height+4);
                }
                    
                WorkingGraph = (TSDGraph)graphManager.addGraph();
                SubNode.setChildGraph(WorkingGraph);
                TSNestingManager.expand(SubNode);
                SubGraphs.Add(xElem.Attributes["BaseElement.SubLongName"].Value, WorkingGraph);
            }


            Rectangle ElemBounds = MM_Serializable<Rectangle>.ConvertObject(xElem.Attributes["Bounds"].Value, null);
            TSDNode NewNode = (TSDNode)WorkingGraph.addNode();
            NewNode.setSize(ElemBounds.Width, ElemBounds.Height);
            NewNode.setCenter(ElemBounds.Left + (ElemBounds.Width / 2), ElemBounds.Top + (ElemBounds.Height / 2));
            NewNode.setUserObject(xElem);
            Elements.Add(xElem, NewNode);

            //If a node, now check for sub-elements as well
            foreach (XmlElement xChild in xElem.ChildNodes)
                if (xChild.HasAttribute("rdfID") && xChild.Name != "Winding")
                {
                    XmlElement TargetElem = xChild.OwnerDocument.SelectSingleNode("One_Line/Elements/" + xChild.Name + "[@rdfID='" + xChild.Attributes["rdfID"].Value + "']") as XmlElement;
                    TSDNode TargetNode = Elements[TargetElem];
                    /*TSDNode TempNode1 = (TSDNode)Graph.addNode();
                    TempNode1.setSize(1, 1);                        
                    TSDNode TargetNode = Elements[TargetElem];
                    LayoutInputTailor.setAttachmentSide(TargetNode, TSLayoutConstants.ATTACHMENT_SIDE_LEFT_OR_RIGHT);
                    TempNode1.setUserObject(new object[] { Graph.addEdge(TargetNode, TempNode1), Graph.addEdge(TempNode1, NewNode) });
                    */

                    TSDEdge NodeRouting = (TSDEdge)graphManager.addEdge(NewNode, TargetNode);
                    
                     
                }
                else if (xChild.Name == "Descriptor" || xChild.Name == "SecondaryDescriptor")
                    AddComponent(xChild, Elements, NewNode, Graph, SubGraphs, graphManager);
            return NewNode;
        }

        /// <summary>
        /// Retrieve a list of nodes that can be processed
        /// </summary>
        /// <param name="NewGraph"></param>
        /// <returns></returns>
        private static List<TSDNode> ExtractNodes(TSDGraph NewGraph)
        {
            List<TSDNode> OutNodes = new List<TSDNode>();
            foreach (TSDNode NodeToProcess in NewGraph.nodes().toArray())
            {
                TSDGraph ChildGraph = NodeToProcess.getChildGraph() as TSDGraph;
                if (ChildGraph != null)
                    foreach (TSDNode SubNodeToProcess in ChildGraph.nodes().toArray())
                        OutNodes.Add(SubNodeToProcess);
                OutNodes.Add(NodeToProcess);
            }
            return OutNodes;
        }

        /// <summary>
        /// Retrieve a list of edges that can be processed
        /// </summary>
        /// <param name="NewGraph"></param>
        /// <returns></returns>
        private static List<TSDEdge> ExtractEdges(TSDGraph NewGraph)
        {
            List<TSDEdge> OutEdges = new List<TSDEdge>();

            foreach (TSDNode Node in NewGraph.nodes().toArray())
                foreach (TSDEdge Edge in Node.getAllIncidentEdges().toArray())
                    OutEdges.Add(Edge);
            //foreach (TSDEdge Edge in NewGraph.edges().toArray())
              //  OutEdges.Add(Edge);
            foreach (TSDNode NodeToProcess in NewGraph.nodes().toArray())
            {
                TSDGraph ChildGraph = NodeToProcess.getChildGraph() as TSDGraph;
                if (ChildGraph != null)
                    foreach (TSDEdge Edge in ChildGraph.edges().toArray())
                        if (!OutEdges.Contains(Edge))
                            OutEdges.Add(Edge);
            }
            return OutEdges;
        }


        /// <summary>
        /// Perform a layout and save the network map
        /// </summary>
        /// <param name="Repository"></param>
        /// <param name="Model"></param>
        /// <param name="TargetFileName"></param>
        public static void LayoutAndSaveNetworkMap(MM_Repository Repository, MM_Database_Model Model, String TargetFileName)
        {
            //Initialize Tom Sawyer
            TSLicenseManager.setUserName(Repository.UserName);
            using (DbCommand dCmd = Repository.Db.CreateCommand("SELECT VALUE FROM MM_CONFIGURATION WHERE \"PARAMETER\"=:0", "TomSawyerLayout"))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                if (dRd.Read())
                {
                    XmlDocument xConfig = new XmlDocument();
                    xConfig.LoadXml((string)dRd["Value"]);
                    java.util.Properties p = new java.util.Properties();
                    foreach (XmlAttribute xAttr in xConfig.DocumentElement.Attributes)
                        p.put(xAttr.Name, xAttr.Value);
                    TSLicenseManager.initTSSLicensing(p); //xConfig.DocumentElement.Attributes["protocol"].Value, xConfig.DocumentElement.Attributes["centralServerHostName"].Value, XmlConvert.ToInt32(xConfig.DocumentElement.Attributes["port"].Value), xConfig.DocumentElement.Attributes["licenseName"].Value,"");
                }

            TSDGraphManager graphManager = new TSDGraphManager();
            TSDGraph NewGraph = (TSDGraph)graphManager.addGraph();
            graphManager.setMainDisplayGraph(NewGraph);
			

            //Add in our substations
            Dictionary<CIM_Element, TSDNode> Substations = new Dictionary<CIM_Element, TSDNode>();
            Dictionary<CIM_Element, TSDEdge> Lines = new Dictionary<CIM_Element, TSDEdge>();
            MM_Substation FoundSub;
            foreach (CIM_Element Substation in Model.Substations.Values)
                if (XmlConvert.ToBoolean(Substation["etx:Substation.forNetwork"]) && XmlConvert.ToBoolean(Substation["etx:Substation.forScada"]))
                    if (!Repository.Db.Substations.TryGetValue(Substation.rdfID, out FoundSub))
                        throw new InvalidOperationException("Unable to locate substation " + Substation.ToString());
                    else
                    {
                        TSDNode NewNode = (TSDNode)NewGraph.addNode();
                        NewNode.setSize(0.2, 0.2);
                        NewNode.setCenter(FoundSub.Longitude, FoundSub.Latitude);
                        NewNode.setUserObject(FoundSub);
                        Substations.Add(Substation, NewNode);
                    }

            //Now, add in our lines
            foreach (CIM_Element Line in Model.ElementsOfType("cim:ACLineSegment"))
            {
                CIM_Element[] Subs = Line.ACSegmentStations;
                Lines.Add(Line, (TSDEdge)NewGraph.addEdge(Substations[Subs[0]], Substations[Subs[1]]));
            }

            //Apply our layout
            TSLayoutProxy layoutProxy = new TSLayoutProxy();
            TSServiceInputData inputData = new TSServiceInputData(TSLayoutServiceName.TYPE);

            TSSymmetricLayoutInputTailor layoutInputTailor = new TSSymmetricLayoutInputTailor(inputData, NewGraph);
           
            //TSOrthogonalLayoutInputTailor layoutInputTailor = new TSOrthogonalLayoutInputTailor(inputData, NewGraph);
            layoutInputTailor.setAsCurrentLayoutStyle();
            TSLayoutInputTailor tailor = new TSLayoutInputTailor(inputData, graphManager);
            tailor.setAsCurrentOperation();

            TSServiceOutputData outputData = new TSServiceOutputData();
            layoutProxy.run(inputData, outputData);
            TSApplyLayoutResults applyResults = new TSApplyLayoutResults();
            applyResults.apply(inputData, outputData);
            //Make sure our subgraphs are included
            java.util.ArrayList nestedGraphs = new java.util.ArrayList();
            TSNestingManager.buildAllNestedGraphList(NewGraph, nestedGraphs, false);
            foreach (TSDGraph childGraph in nestedGraphs)
                inputData.setOption(childGraph, TSBaseGeneralLayoutConstants.LAYOUT_STYLE, TSLayoutConstants.LAYOUT_STYLE_ORTHOGONAL);


            //Determine our bounds of our updated components
            Point MinPoint = Point.Empty;
            foreach (TSDNode Node in ExtractNodes(NewGraph))
            {
                MinPoint.X = Math.Min(MinPoint.X, (int)Node.getLeft());
                MinPoint.Y = Math.Min(MinPoint.Y, -(int)Node.getBottom());
            }

            //Adjust all of our nodes
            foreach (TSDNode Node in Substations.Values)            
                Node.setCenter((int)Node.getCenterX() - MinPoint.X, (int)-Node.getCenterY() + 80 - MinPoint.Y);

            MinPoint = new Point(int.MaxValue, int.MaxValue);
            Point MaxPoint = new Point(int.MinValue, int.MinValue);
            foreach (TSDNode Node in Substations.Values)
            {
                MinPoint.X = Math.Min(MinPoint.X, (int)Node.getLeft());
                MinPoint.Y = Math.Min(MinPoint.Y, (int)Node.getBottom());
                MaxPoint.X = Math.Max(MaxPoint.X, (int)Node.getLeft());
                MaxPoint.Y = Math.Max(MaxPoint.Y, (int)Node.getBottom());
            }

            MinPoint.X += 10;
            MinPoint.Y += 10;

            //Adjust all of our nodes
            foreach (TSDNode Node in Substations.Values)
                Node.setCenter((int)Node.getCenterX() - MinPoint.X, (int)-Node.getCenterY() - MinPoint.Y);

      
            //Write our SVG document
            using (XmlTextWriter xW = new XmlTextWriter(TargetFileName, Encoding.UTF8))
            {
                xW.Formatting = Formatting.Indented;
                xW.WriteStartDocument(false);
                xW.WriteDocType("svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null);
                xW.WriteStartElement("svg", "http://www.w3.org/2000/svg");
                xW.WriteAttributeString("width", (300+MaxPoint.X - MinPoint.X).ToString());
                xW.WriteAttributeString("height", (300+MaxPoint.Y - MinPoint.Y).ToString());
                xW.WriteAttributeString("version", "1.1");
                xW.WriteElementString("title","Macomber Map Auto-Layout: " + Model.ToString());
                /*
                xW.WriteStartElement("defs");
                xW.WriteStartElement("marker");
                xW.WriteAttributeString("id", "endArrow");
                xW.WriteAttributeString("viewBox", "0 0 10 10");
                xW.WriteAttributeString("refX", "1");
                xW.WriteAttributeString("refY", "5");
                xW.WriteAttributeString("markerUnits", "strokeWidth");
                xW.WriteAttributeString("orient", "auto");
                xW.WriteAttributeString("markerWidth", "5");
                xW.WriteAttributeString("markerHeight", "4");
                xW.WriteStartElement("polyline");
                xW.WriteAttributeString("points", "0,0 10,5 0,10 1,5");
                xW.WriteAttributeString("fill", "black");
                xW.WriteEndElement();
                xW.WriteEndElement();
                xW.WriteStartElement("marker");
                xW.WriteAttributeString("id", "startArrow");
                xW.WriteAttributeString("viewBox", "0 0 10 10");
                xW.WriteAttributeString("refX", "1");
                xW.WriteAttributeString("refY", "5");
                xW.WriteAttributeString("markerUnits", "strokeWidth");
                xW.WriteAttributeString("orient", "auto");
                xW.WriteAttributeString("markerWidth", "5");
                xW.WriteAttributeString("markerHeight", "4");
                xW.WriteStartElement("polyline");
                xW.WriteAttributeString("points", "10,0 0,5 10,10 9,5");
                xW.WriteAttributeString("fill", "black");
                xW.WriteEndElement();
                xW.WriteEndElement();
                xW.WriteEndElement();
                */

                //First, write out our lines, then our substations
                foreach (KeyValuePair<CIM_Element, TSDEdge> kvp in Lines)
                    WriteLine(xW, kvp.Value, kvp.Key);
                foreach (KeyValuePair<CIM_Element, TSDNode> kvp in Substations)
                {
                    bool FoundUnit = false;
                    foreach (CIM_Element Elem in kvp.Key.Elements)
                        if (Elem.TypeName == "cim:SynchronousMachine")
                            FoundUnit = true;
                    Point Location = new Point((int)kvp.Value.getCenterX(), -(int)kvp.Value.getCenterY());

                    if (FoundUnit) //(kvp.Key.ElementTypes | MM_OneLine_Element.enumElemTypes.Unit) == MM_OneLine_Element.enumElemTypes.Unit)
                    {
                        xW.WriteStartElement("polygon");
                        int PolySize = 6;
                        xW.WriteAttributeString("points", String.Format("{0},{5} {4},{1} {2},{5} {4},{3}", Location.X - PolySize, Location.Y - PolySize, Location.X + PolySize, Location.Y + PolySize, Location.X, Location.Y));
                    }
                    else
                    {
                        xW.WriteStartElement("circle");
                        xW.WriteAttributeString("cx", (Location.X).ToString());
                        xW.WriteAttributeString("cy", (Location.Y).ToString());
                        xW.WriteAttributeString("r", "4");
                    }
                    xW.WriteAttributeString("stroke", "black");
                    xW.WriteAttributeString("stroke-width", "2");
                    xW.WriteAttributeString("fill", "red");
                    xW.WriteElementString("title", kvp.Key.GetPopupText());
                    xW.WriteEndElement();
                }
                xW.WriteEndElement();
                xW.Flush();
                xW.Close();
            }
            
        }

        /// <summary>
        /// Write an SVG line between two points
        /// </summary>
        /// <param name="xW">The XML text writer</param>
        /// <param name="Edge">The edge to draw</param>
        /// <param name="Line"></param>
        private static void WriteLine(XmlTextWriter xW, TSDEdge Edge, CIM_Element Line)
        {
            //Determine our points
            Rectangle SourceRect = new Rectangle((int)Edge.getSourceCenter().getX()-2, -(int)Edge.getSourceCenter().getY()-2,4,4);
            Rectangle TargetRect = new Rectangle((int)Edge.getTargetCenter().getX()-2, -(int)Edge.getTargetCenter().getY()-2,4,4);
            Point StartPoint = new Point(SourceRect.X + (SourceRect.Width / 2), SourceRect.Y + (SourceRect.Height / 2));
            Point EndPoint = new Point(TargetRect.X + (TargetRect.Width / 2), TargetRect.Y + (TargetRect.Height / 2));

            if (TargetRect.Top > SourceRect.Bottom)
                EndPoint.Y = TargetRect.Top;
            else if (SourceRect.Top > TargetRect.Bottom)
                EndPoint.Y = TargetRect.Bottom;
            if (TargetRect.Left > SourceRect.Right)
                EndPoint.X = TargetRect.Left;
            else if (SourceRect.Left > TargetRect.Right)
                EndPoint.X = TargetRect.Right;

            if (SourceRect.Top > TargetRect.Bottom)
                StartPoint.Y = SourceRect.Top;
            else if (TargetRect.Top > SourceRect.Bottom)
                StartPoint.Y = SourceRect.Bottom;
            if (SourceRect.Left > TargetRect.Right)
                StartPoint.X = SourceRect.Left;
            else if (TargetRect.Left > SourceRect.Right)
                StartPoint.X = SourceRect.Right;


            xW.WriteStartElement("line");
            xW.WriteAttributeString("x1", StartPoint.X.ToString());
            xW.WriteAttributeString("y1", StartPoint.Y.ToString());
            xW.WriteAttributeString("x2", EndPoint.X.ToString());
            xW.WriteAttributeString("y2", EndPoint.Y.ToString());                        
            xW.WriteAttributeString("stroke", ColorTranslator.ToHtml(Data_Manager.LocateKVLevel(Line.VoltageLevel).Energized.ForeColor));
            xW.WriteAttributeString("stroke-width", "3");
            xW.WriteElementString("title", Line.GetPopupText());
            /*if (DualArrows)
                xW.WriteAttributeString("marker-start", "url(#startArrow)");
            xW.WriteAttributeString("marker-end", "url(#endArrow)");*/
            xW.WriteEndElement();
        }

        /// <summary>
        /// Pull our TSL information back into XML
        /// </summary>
        /// <param name="NewGraph"></param>
        /// <param name="MinPoint"></param>
        /// <param name="xOneLine"></param>
        private static void PullLayoutToXml(TSDGraph NewGraph, Point MinPoint, XmlDocument xOneLine)
        {
            //Adjust our points a bit
            MinPoint -= new Size(10, 10);

            //Update our node positions
            List<Rectangle> Rects = new List<Rectangle>();
            foreach (TSDNode Node in ExtractNodes(NewGraph))
                if (Node.getUserObject() is string)
                {
                    //Make sure our unlinked element is present
                    XmlElement xUnlinked = xOneLine.DocumentElement["Unlinked_Elements"];
                    if (xUnlinked == null)
                        xUnlinked = xOneLine.DocumentElement.AppendChild(xOneLine.CreateElement("Unlinked_Elements")) as XmlElement;

                    //Add in a rectangle around our substation
                    Point NewCenter = new Point((int)Node.getCenterX() - MinPoint.X, (int)-Node.getCenterY() + 80 - MinPoint.Y);
                    Size NewSize = new Size((int)Node.getWidth(), (int)Node.getHeight());
                    XmlElement xRect = xUnlinked.AppendChild(xOneLine.CreateElement("Rectangle")) as XmlElement;
                    xRect.Attributes.Append(xOneLine.CreateAttribute("Bounds")).Value = String.Format("{0:0},{1:0},{2:0},{3:0}", NewCenter.X - (NewSize.Width / 2), NewCenter.Y - (NewSize.Height / 2), NewSize.Width, NewSize.Height);
                    xRect.Attributes.Append(xOneLine.CreateAttribute("BackColor")).Value = "Transparent";

                    //Add in our label

                    TSLabel Lbl = Node.labels().get(0) as TSLabel;
                    NewCenter = new Point((int)Lbl.getCenterX() - MinPoint.X, (int)-Lbl.getCenterY() + 80 - MinPoint.Y);
                    NewSize = new Size((int)Lbl.getWidth(), (int)Lbl.getHeight());
                    XmlElement xLbl = xUnlinked.AppendChild(xOneLine.CreateElement("Label")) as XmlElement;
                    xLbl.Attributes.Append(xOneLine.CreateAttribute("Bounds")).Value = String.Format("{0:0},{1:0},{2:0},{3:0}", NewCenter.X - (NewSize.Width / 2), NewCenter.Y - (NewSize.Height / 2), NewSize.Width, NewSize.Height);
                    xLbl.Attributes.Append(xOneLine.CreateAttribute("Text")).Value = Lbl.getText();
                    xLbl.Attributes.Append(xOneLine.CreateAttribute("Font")).Value = "Arial, 12pt, style=Bold";
                }
                else
                {
                    XmlElement NewElem = Node.getUserObject() as XmlElement;
                    Point NewCenter = new Point((int)Node.getCenterX() - MinPoint.X, (int)-Node.getCenterY() + 80 - MinPoint.Y);
                    Size NewSize = new Size((int)Node.getWidth(), (int)Node.getHeight());
                    NewElem.Attributes["Bounds"].Value = String.Format("{0:0},{1:0},{2:0},{3:0}", NewCenter.X - (NewSize.Width / 2), NewCenter.Y - (NewSize.Height / 2), NewSize.Width, NewSize.Height);
                }

            foreach (TSDEdge Edge in ExtractEdges(NewGraph))
            {
                TSDNode SourceNode = Edge.getSourceNode() as TSDNode;
                XmlElement SourceElem = SourceNode.getUserObject() as XmlElement;

                TSDNode TargetNode = Edge.getTargetNode() as TSDNode;
                XmlElement TargetElem = TargetNode.getUserObject() as XmlElement;

                XmlElement SourceToTarget = SourceElem.SelectSingleNode(TargetElem.Name + "[@rdfID='" + TargetElem.Attributes["rdfID"].Value + "']") as XmlElement;
                Point SourcePoint = new Point((int)SourceNode.getCenterX() - MinPoint.X, (int)SourceNode.getCenterY() + 80 - MinPoint.Y);
                Rectangle SourceRect = new Rectangle(SourcePoint, new Size((int)SourceNode.getWidth(), (int)SourceNode.getHeight()));
                Point TargetPoint = new Point((int)TargetNode.getCenterX() - MinPoint.X, (int)TargetNode.getCenterY() + 80 - MinPoint.Y);
                Rectangle TargetRect = new Rectangle(TargetPoint, new Size((int)TargetNode.getWidth(), (int)TargetNode.getHeight()));

              

                foreach (TSConstPoint NextPoint in Edge.bendPoints().toArray())
                {
                    XmlElement NewPoke = SourceElem.OwnerDocument.CreateElement("PokePoint");
                    Point PokeCenter = new Point((int)NextPoint.getX() - MinPoint.X, (int)-NextPoint.getY() + 80 - MinPoint.Y);
                    NewPoke.Attributes.Append(NewPoke.OwnerDocument.CreateAttribute("Bounds")).Value = String.Format("{0},{1},{2},{3}", PokeCenter.X - 2, PokeCenter.Y - 2, 4, 4);
                    foreach (XmlAttribute xAttr in SourceElem.Attributes)
                        if (xAttr.Name.StartsWith("BaseElement") || xAttr.Name == "rdfID")
                            NewPoke.Attributes.Append(NewPoke.OwnerDocument.CreateAttribute(xAttr.Name)).Value = xAttr.Value;
                    NewPoke.Attributes.Append(NewPoke.OwnerDocument.CreateAttribute("IsVisible")).Value = "false";

                    SourceToTarget.AppendChild(NewPoke);
                    SourcePoint = PokeCenter;
                }
            }

            //Go through our nodes, and pull together our paths.
            foreach (XmlElement xNode in xOneLine.SelectNodes("One_Line/Nodes/Node"))
            {
                Rects.Add(MM_Serializable<Rectangle>.ConvertObject(xNode.Attributes["Bounds"].Value, null));
                foreach (XmlElement xNodeCh in xNode.ChildNodes)
                    if (!xNodeCh.Name.EndsWith("Descriptor"))
                        foreach (KeyValuePair<PointF, PointF> kvp in MM_HitTesting.ExtractLines(MM_OneLine_Element.BuildNodePath(xNode, xNodeCh)))
                        {
                            Rectangle NewRect = Rectangle.FromLTRB((int)Math.Min(kvp.Key.X, kvp.Value.X), (int)Math.Min(kvp.Key.Y, kvp.Value.Y), (int)Math.Max(kvp.Key.X, kvp.Value.X), (int)Math.Max(kvp.Key.Y, kvp.Value.Y));
                            NewRect.Width = Math.Max(1, NewRect.Width);
                            NewRect.Height = Math.Max(1, NewRect.Height);
                            Rects.Add(NewRect);
                        }
            }

            //Pull in our descriptor locations
            foreach (TSDNode Node in ExtractNodes(NewGraph))
                if (Node.getChildGraph() == null)
                foreach (TSLabel Label in Node.labels().toArray())
                {
                    XmlElement xDesc = Label.getUserObject() as XmlElement;
                    Point NewCenter = new Point((int)Label.getCenterX() - MinPoint.X, (int)-Label.getCenterY() + 80 - MinPoint.Y);
                    Size NewSize = new Size((int)Label.getWidth(), (int)Label.getHeight());
                    Size EstSize;
                    using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
                        EstSize = g.MeasureString(xDesc.Attributes["DescriptorText"].Value, SystemFonts.CaptionFont).ToSize();
                    if (xDesc.HasAttribute("LabelBounds"))                    
                        xDesc.Attributes["LabelBounds"].Value = String.Format("{0:0},{1:0},{2:0},{3:0}", NewCenter.X - (NewSize.Width / 2), NewCenter.Y - (NewSize.Height / 2), NewSize.Width, NewSize.Height);
                    Rectangle ParentBounds = MM_Serializable<Rectangle>.ConvertObject(xDesc.ParentNode.Attributes["Bounds"].Value, null);
                    Rectangle LabelBounds = new Rectangle(NewCenter.X - (NewSize.Width / 2), NewCenter.Y - (NewSize.Height / 2), NewSize.Width, NewSize.Height);

                    //If our element intersects the label, at an edge or within, shift the label.
                    bool ToLeft = LabelBounds.Right <= ParentBounds.Left;
                    bool ToRight = LabelBounds.Left >= ParentBounds.Right;
                    bool ToTop = LabelBounds.Bottom <= ParentBounds.Top;
                    bool ToBottom = LabelBounds.Top >= ParentBounds.Bottom;

                    if (LabelBounds.Left <= ParentBounds.Left && LabelBounds.Right >= ParentBounds.Right)
                        LabelBounds.X = ParentBounds.Left + (ParentBounds.Width / 2) - (EstSize.Width / 2);
                    else if (ToLeft && ToRight)
                        LabelBounds.X = ParentBounds.Left + (ParentBounds.Width / 2) - (EstSize.Width / 2);
                    else if (ToLeft)
                        LabelBounds.X = ParentBounds.Left - EstSize.Width - 2;
                    else if (ToRight)
                        LabelBounds.X = ParentBounds.Right + 2;

                    if (LabelBounds.Top <= ParentBounds.Top && LabelBounds.Bottom >= ParentBounds.Bottom)
                        LabelBounds.Y = ParentBounds.Top + (ParentBounds.Height / 2) - (EstSize.Height / 2);
                    else if (LabelBounds.Top >= ParentBounds.Top && LabelBounds.Bottom <= ParentBounds.Bottom)
                        LabelBounds.Y = ParentBounds.Top + (ParentBounds.Height / 2) - (EstSize.Height / 2);
                    else if (ToTop && ToBottom)
                    { }
                    else if (ToTop)
                        LabelBounds.Y = ParentBounds.Top - EstSize.Height - 2;
                    else if (ToBottom)
                        LabelBounds.Y = ParentBounds.Bottom + 2;

                    LabelBounds.Size = EstSize;

                    xDesc.Attributes["Bounds"].Value = String.Format("{0:0},{1:0},{2:0},{3:0}", LabelBounds.Left, LabelBounds.Top, LabelBounds.Width, LabelBounds.Height);

                }


        }
    }
}